package com.aat.dxfy.game.j46810.perfect;


/*
 * @power dizena.com
 * @time 2014-08-06
 * @version 1.0
 */

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

/**
 * @author 新歌
 * @date 2016年7月6日 下午8:27:55
 * @info 
 * @params 
 * @return
 */
public class Game46810 extends JPanel {
	/**
	 * 类型继承JAVA的面板
	 */

	// 定义一些私有属性
	private static final long serialVersionUID = 1L;
	private static final Color BG_COLOR = new Color(0xbbada0);// 颜色
	private static final int TILE_SIZE = 64;// 大小
	private static final int TILES_MARGIN = 16;// 边距

	private Tile[] myTiles;// 瓷砖块数组
	boolean myWin = false;// 是否赢了
	boolean myLose = false;// 输了
	int myScore = 0;// 得分
	int level = 4;// 默认级别
	private int allScore = 2048;
	private int[][] alalysisArys;// 瓷砖块数组
	private int[][] beforeArys;// 瓷砖块数组
	int key = 0;// 默认日志类型
	long times = 0;// 走动次数
	boolean pauseRun = true;// 暂停
	Thread autoT = null;
	Thread pauseT = null;

	class AutoThread extends Thread {
		public void run() {
			autoRun();
		}
	}

	class PauseThread extends Thread {
		public void run() {
			pauseRun = false;
		}
	}

	public Game46810(int level) {
		this.level = level;
		alalysisArys = new int[level][level];
		beforeArys = new int[level][level];
		// 聚焦
		setFocusable(true);

		// 添加键盘事件,匿名内部类实现
		addKeyListener(new KeyAdapter() {

			public void keyPressed(KeyEvent e) {
				// 退出键，重新开始
				if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					resetGame();
				}
				// 回车键，自动运行
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					autoT = new AutoThread();
					autoT.start();
				}
				// 回车键，自动运行
				if (e.getKeyCode() == KeyEvent.VK_SPACE) {
					pauseT = new PauseThread();
					pauseT.start();
				}

				if (!canMove()) {
					myLose = true;
				}

				// 移动，上下左右
				if (!myWin && !myLose) {
					switch (e.getKeyCode()) {
					case KeyEvent.VK_LEFT:
						left();
						break;
					case KeyEvent.VK_RIGHT:
						right();
						break;
					case KeyEvent.VK_DOWN:
						down();
						break;
					case KeyEvent.VK_UP:
						up();
						break;
					}
				}

				// 输了
				if (!myWin && !canMove()) {
					myLose = true;
				}

				// 画笔勾勒
				repaint();
			}

		});
		// 开始游戏
		resetGame();
	}

	// 重置游戏
	public void resetGame() {
		myScore = 0;
		myWin = false;
		myLose = false;
		myTiles = new Tile[level * level];
		for (int i = 0; i < myTiles.length; i++) {
			myTiles[i] = new Tile();
		}
		// 增加两个是初始化
		addTile();
		addTile();
	}

	// 自动玩游戏
	private void autoRun() {
		// 是否第一步
		boolean num1steap = true;
		for (int i = 0; i < alalysisArys.length; i++) {
			for (int j = 0; j < alalysisArys[0].length; j++) {
				if (0 != alalysisArys[i][j]) {
					num1steap = false;
				}
			}
		}
		if (num1steap) {
			down();
		}

		// 计算
		pauseRun = true;
		while (pauseRun) {
			if (myWin == true || isFull() == true) {
				pauseRun = false;
				// 成功
				JOptionPane.showMessageDialog(null, "挑战得分:" + myScore, "游戏",
						JOptionPane.PLAIN_MESSAGE);
				resetGame();
			}
			// 一维数组记录线性
			int notzreonum = 0;// 非0个数
			int arys1[] = new int[level * level];

			System.out.println("-------------------------------");
			for (int i = 0; i < alalysisArys.length; i++) {
				System.out.println(Arrays.toString(alalysisArys[i]));
				for (int j = 0; j < alalysisArys[0].length; j++) {
					arys1[i * j + j] = alalysisArys[i][j];
					if (0 != alalysisArys[i][j])
						notzreonum++;
				}
			}
			// 排序一维数组
			Arrays.sort(arys1);
			System.out.println(Arrays.toString(arys1) + "  " + notzreonum);

			// 0，采用积分移动原则。
			// 1.1，大数在[0][0],[0][level-1],[level-1][0],[level-1][level-1],加上level分。
			// 1.2，大数在,[0][1],[1][0]...（level-1）分，同理下去。

			// 2.1,相邻相等积分，有几对加几分。
			// 2.2,相邻相等，是多少指数倍加几分。例如：32=2^5,有此相邻加5分。
			// 加分数有方向，最高的那处移动。
			int left = 0, right = 0, up = 0, down = 0;

			// 左右相邻评分计算
			for (int i = 0; i < alalysisArys.length; i++) {
				int j = 0;
				while (j < level) {
					int k = j + 1;
					int num = alalysisArys[i][j];
					if (num != 0) {
						for (; k < level; k++) {
							if (num == alalysisArys[i][k]) {
								left += level;
								break;
							} else {
								if (alalysisArys[i][k] == 0)
									continue;
								else
									break;
							}
						}
						j = k;
					} else {
						j++;
					}
				}
			}
			right = left;

			// 上下相邻评分
			for (int i = 0; i < level; i++) {
				int j = 0;
				while (j < level) {
					int k = j + 1;
					int num = alalysisArys[j][i];
					if (num != 0) {
						for (; k < level; k++) {
							if (num == alalysisArys[k][i]) {
								up += 2;
								break;
							} else {
								if (alalysisArys[k][i] == 0)
									continue;
								else
									break;
							}
						}
						j = k;
					} else {
						j++;
					}
				}
			}
			down = up;
			System.out.println("left:" + left + ",right:" + right + ",up:" + up
					+ ",down:" + down);

			// 区域评分
			int qleft = 0, qright = 0, qup = 0, qdown = 0;
			for (int i = arys1.length - 1; i > -1; i--) {
				if (arys1[i] != 0) {
					// 上左右
					for (int j = 0; j < level / 2; j++) {
						for (int k = 0; k < level / 2; k++) {
							if (alalysisArys[j][k] == arys1[i]) {
								int tmp = (level - k - j + 2 * i);
								qleft += tmp;
								qup += tmp;
							}
						}
						for (int m = level / 2; m < level; m++) {
							if (alalysisArys[j][m] == arys1[i]) {
								int tmp = (m - j + 1 + 2 * i);
								qright += tmp;
								qup += tmp;
							}
						}
					}
					// 下左右
					for (int j = level / 2; j < level; j++) {
						for (int k = 0; k < level / 2; k++) {
							if (alalysisArys[j][k] == arys1[i]) {
								int tmp = (1 + j - k + 2 * i);
								qdown += tmp;
								qleft += tmp;
							}
						}
						for (int m = level / 2; m < level; m++) {
							if (alalysisArys[j][m] == arys1[i]) {
								int tmp = (j + m + 2 - level / 2 + 2 * i);
								qdown += tmp;
								qright += tmp;
							}
						}
					}
				}
			}

			System.out.println("qleft:" + qleft + ",qright:" + qright + ",up:"
					+ qup + ",qdown:" + qdown);

			// 移动
			beforeArys = deepCopy(alalysisArys);
			int[] ary = { qleft, qright, qup, qdown };
			int action = 0;// 0123,左右上下
			if (left == 0 && up == 0) {
				if (isMax(qleft, ary)) {
					action = 0;
				} else if (isMax(qright, ary)) {
					action = 1;
				} else if (isMax(qup, ary)) {
					action = 2;
				} else {
					action = 3;
				}
			} else if (left == 0 && up != 0) {
				if (qup > qdown) {
					action = 2;
				} else {
					action = 3;
				}
			} else if (left != 0 && up == 0) {
				if (qleft > qright) {
					action = 0;
				} else {
					action = 1;
				}
			} else if (left != 0 && up != 0) {
				if (left > up) {
					if (qleft > qright) {
						action = 0;
					} else {
						action = 1;
					}
				} else {
					if (qup > qdown) {
						action = 2;
					} else {
						action = 3;
					}
				}

			}

			if (action == 0) {
				left();
			} else if (action == 1) {
				right();
			} else if (action == 2) {
				up();
			} else {
				down();
			}
			if (Arrays.deepEquals(beforeArys, alalysisArys)) {
				left();
				if (Arrays.deepEquals(beforeArys, alalysisArys)) {
					right();
					if (Arrays.deepEquals(beforeArys, alalysisArys)) {
						down();
						if (Arrays.deepEquals(beforeArys, alalysisArys)) {
							up();
						}
					}
				}
			}
			// 画笔勾勒
			repaint();
			// 休眠1秒钟
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	private int[][] deepCopy(int[][] board) {
		int[][] copy = new int[board.length][board[0].length];
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[0].length; j++) {
				copy[i][j] = board[i][j];
			}
		}
		return copy;
	}

	// 是最大吗
	public boolean isMax(int x, int[] ary) {
		Arrays.sort(ary);
		if (x == ary[ary.length - 1])
			return true;
		return false;
	}

	// 打印日志,得到可分析二维数组
	public int[][] echoLog() {
		times++;
		Tile[][] tmp = null;
		if (0 == key) {
			// 左
			tmp = oneAry2TwoAry(myTiles);
		} else if (1 == key) {
			// 右
			tmp = transferMatrix(transferMatrix(oneAry2TwoAry(myTiles)));
		} else if (2 == key) {
			// 上
			tmp = transferMatrix(oneAry2TwoAry(myTiles));
		} else {
			// 下
			tmp = transferMatrix(transferMatrix(transferMatrix(oneAry2TwoAry(myTiles))));
		}

		for (int i = 0; i < tmp.length; i++) {
			for (int j = 0; j < tmp[0].length; j++) {
				alalysisArys[i][j] = tmp[i][j].value;
			}

		}
		int[][] alalysisArys = new int[level][level];
		return alalysisArys;
	}

	// 一维转二维
	public Tile[][] oneAry2TwoAry(Tile[] tiles) {
		Tile[][] ts = new Tile[level][level];
		for (int i = 0; i < tiles.length; i++) {
			ts[i / level][i % level] = tiles[i];
		}
		return ts;
	}

	// 矩阵转秩
	public Tile[][] transferMatrix(Tile[][] matrix) {
		int x = matrix.length;
		int y = matrix[0].length;
		Tile ary2[][] = new Tile[y][x];
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				ary2[j][x - 1 - i] = matrix[i][j];
			}
		}
		return ary2;
	}

	// 左移动
	public void left() {
		boolean needAddTile = false;
		for (int i = 0; i < level; i++) {
			Tile[] line = getLine(i);
			Tile[] merged = mergeLine(moveLine(line));
			setLine(i, merged);
			if (!needAddTile && !compare(line, merged)) {
				needAddTile = true;
			}
		}

		if (needAddTile) {
			addTile();
		}
		echoLog();
		key = 0;
	}

	public void right() {
		key = 1;
		myTiles = rotate(180);
		left();
		myTiles = rotate(180);
	}

	public void up() {
		key = 2;
		myTiles = rotate(270);
		left();
		myTiles = rotate(90);
	}

	public void down() {
		key = 3;
		myTiles = rotate(90);
		left();
		myTiles = rotate(270);
	}

	private Tile tileAt(int x, int y) {
		return myTiles[x + y * level];
	}

	// 增加
	private void addTile() {
		List<Tile> list = availableSpace();
		if (!availableSpace().isEmpty()) {
			int index = (int) (Math.random() * list.size()) % list.size();
			Tile emptyTime = list.get(index);
			emptyTime.value = Math.random() < 0.9 ? 2 : 4;
		}
	}

	// 磁砖的数量
	private List<Tile> availableSpace() {
		final List<Tile> list = new ArrayList<Tile>(level * level);
		for (Tile t : myTiles) {
			if (t.isEmpty()) {
				list.add(t);
			}
		}
		return list;
	}

	// 判断是否满了
	private boolean isFull() {
		return availableSpace().size() == 0;
	}

	// 是否可以移动
	boolean canMove() {
		if (!isFull()) {
			return true;
		}
		for (int x = 0; x < level; x++) {
			for (int y = 0; y < level; y++) {
				Tile t = tileAt(x, y);
				if ((x < level - 1 && t.value == tileAt(x + 1, y).value)
						|| ((y < level - 1) && t.value == tileAt(x, y + 1).value)) {
					return true;
				}
			}
		}
		return false;
	}

	// 比较两个相邻 的磁块大小
	private boolean compare(Tile[] line1, Tile[] line2) {
		if (line1 == line2) {
			return true;
		} else if (line1.length != line2.length) {
			return false;
		}

		for (int i = 0; i < line1.length; i++) {
			if (line1[i].value != line2[i].value) {
				return false;
			}
		}
		return true;
	}

	// 转动方向
	private Tile[] rotate(int angle) {
		Tile[] newTiles = new Tile[level * level];
		int offsetX = level - 1, offsetY = level - 1;
		if (angle == 90) {
			offsetY = 0;
		} else if (angle == 270) {
			offsetX = 0;
		}

		double rad = Math.toRadians(angle);
		int cos = (int) Math.cos(rad);
		int sin = (int) Math.sin(rad);
		for (int x = 0; x < level; x++) {
			for (int y = 0; y < level; y++) {
				int newX = (x * cos) - (y * sin) + offsetX;
				int newY = (x * sin) + (y * cos) + offsetY;
				newTiles[(newX) + (newY) * level] = tileAt(x, y);
			}
		}
		return newTiles;
	}

	// 移动线路
	private Tile[] moveLine(Tile[] oldLine) {
		LinkedList<Tile> l = new LinkedList<Tile>();
		for (int i = 0; i < level; i++) {
			if (!oldLine[i].isEmpty())
				l.addLast(oldLine[i]);
		}
		if (l.size() == 0) {
			return oldLine;
		} else {
			Tile[] newLine = new Tile[level];
			ensureSize(l, level);
			for (int i = 0; i < level; i++) {
				newLine[i] = l.removeFirst();
			}
			return newLine;
		}
	}

	// 合并路线
	private Tile[] mergeLine(Tile[] oldLine) {
		LinkedList<Tile> list = new LinkedList<Tile>();
		for (int i = 0; i < level && !oldLine[i].isEmpty(); i++) {
			int num = oldLine[i].value;
			if (i < level - 1 && oldLine[i].value == oldLine[i + 1].value) {
				num *= 2;
				myScore += num;
				int ourTarget = allScore;
				if (num == ourTarget) {
					myWin = true;
				}
				i++;
			}
			list.add(new Tile(num));
		}
		if (list.size() == 0) {
			return oldLine;
		} else {
			ensureSize(list, level);
			return list.toArray(new Tile[level]);
		}
	}

	// 允许的大小
	private static void ensureSize(java.util.List<Tile> l, int s) {
		while (l.size() != s) {
			l.add(new Tile());
		}
	}

	// 获得线路
	private Tile[] getLine(int index) {
		Tile[] result = new Tile[level];
		for (int i = 0; i < level; i++) {
			result[i] = tileAt(i, index);
		}
		return result;
	}

	// 设置线路
	private void setLine(int index, Tile[] re) {
		System.arraycopy(re, 0, myTiles, index * level, level);
	}

	// 调用Java画笔工具进行画图
	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(BG_COLOR);
		g.fillRect(0, 0, this.getSize().width, this.getSize().height);
		for (int y = 0; y < level; y++) {
			for (int x = 0; x < level; x++) {
				drawTile(g, myTiles[x + y * level], x, y);
			}
		}
	}

	// 开始划线，写字，计分
	private void drawTile(Graphics g2, Tile tile, int x, int y) {
		Graphics2D g = ((Graphics2D) g2);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
				RenderingHints.VALUE_STROKE_NORMALIZE);
		int value = tile.value;
		int xOffset = offsetCoors(x);
		int yOffset = offsetCoors(y);
		g.setColor(tile.getBackground());
		g.fillRoundRect(xOffset, yOffset, TILE_SIZE, TILE_SIZE, 14, 14);
		g.setColor(tile.getForeground());
		final int size = value < 100 ? 36 : value < 1000 ? 32 : 24;
		final Font font = new Font(null, Font.BOLD, size);
		g.setFont(font);

		String s = String.valueOf(value);
		final FontMetrics fm = getFontMetrics(font);

		final int w = fm.stringWidth(s);
		final int h = -(int) fm.getLineMetrics(s, g).getBaselineOffsets()[2];

		if (value != 0)
			g.drawString(s, xOffset + (TILE_SIZE - w) / 2, yOffset + TILE_SIZE
					- (TILE_SIZE - h) / 2 - 2);

		if (myWin || myLose) {
			g.setColor(new Color(255, 255, 255, 30));
			g.fillRect(0, 0, getWidth(), getHeight());
			g.setColor(new Color(78, 139, 202));
			g.setFont(new Font(null, Font.BOLD, 48));
			if (myWin) {
				g.drawString("恭喜你赢了!", 68, 150);
			}
			if (myLose) {
				g.drawString("游戏结束!", 50, 130);
				g.drawString("你失败了!", 64, 200);
			}
			if (myWin || myLose) {
				g.setFont(new Font(null, Font.PLAIN, 16));
				g.setColor(new Color(128, 128, 128, 128));
				g.drawString("按ESC重新开始", 80, getHeight() - 40);
			}
		}
		g.setFont(new Font(null, Font.PLAIN, 18));
		g.setColor(Color.red);
		g.drawString("ESC:重来,ENTER:自动,SPACE:暂停", 10, 80 * level + 20);
		g.drawString("上下左右：玩!", 10, 80 * level + 45);
		g.drawString("分数: " + myScore, 100 * level / 2, 80 * level + 45);

	}

	// 重置颜色
	private static int offsetCoors(int i) {
		return i * (TILES_MARGIN + TILE_SIZE) + TILES_MARGIN;
	}

	// 启动游戏
	public static void main(String[] args) {
		Object[] obj = { "4", "6", "8", "10" };
		String s = (String) JOptionPane.showInputDialog(null, "请选择游戏级别:\n",
				"4-6-8-10游戏", JOptionPane.PLAIN_MESSAGE, null, obj, null);
		int level = Integer.parseInt(s);

		JFrame game = new JFrame();
		game.setTitle("2048游戏和自动");
		game.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		game.setResizable(false);
		game.setSize(80 * level + 20, 100 * level);
		game.add(new Game46810(level));

		game.setLocationRelativeTo(null);
		game.setVisible(true);
	}
}

// 定义一个内部磁砖块
class Tile {
	/**
	 * 磁砖块的颜色取值
	 */
	int value;

	public Tile() {
		this(0);
	}

	public Tile(int num) {
		value = num;
	}

	public boolean isEmpty() {
		return value == 0;
	}

	public Color getForeground() {
		return value < 16 ? new Color(0x776e65) : new Color(0xf9f6f2);
	}

	public Color getBackground() {
		switch (value) {
		case 2:
			return new Color(0xeee4da);
		case 4:
			return new Color(0xede0c8);
		case 8:
			return new Color(0xf2b179);
		case 16:
			return new Color(0xf59563);
		case 32:
			return new Color(0xf67c5f);
		case 64:
			return new Color(0xf65e3b);
		case 128:
			return new Color(0xedcf72);
		case 256:
			return new Color(0xedcc61);
		case 512:
			return new Color(0xedc850);
		case 1024:
			return new Color(0xedc53f);
		case 2048:
			return new Color(0xedc22e);
		case 4096:
			return new Color(0xedc11d);
		case 8192:
			return new Color(0xedc00c);
		}
		return new Color(0xcdc1b4);
	}

}
